package logkit

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"time"

	"github.com/sirupsen/logrus"
	"github.com/xuelang-group/suanpan-appconnector/pkg/common"
	"github.com/xuelang-group/suanpan-appconnector/pkg/suanpan_log"
	"github.com/xuelang-group/suanpan-appconnector/pkg/util"
)

type logData struct {
	Node string `json:"node"`
}

type LogInfo struct {
	Title string  `json:"title"`
	Level string  `json:"level"`
	Time  string  `json:"time"`
	Data  logData `json:"data"`
}

type logKitPostMasterData struct {
	Appid string          `json:"app"`
	Logs  json.RawMessage `json:"logs"`
}

var logJobCh chan *LogInfo

type LogKitHandler func(info *LogInfo) error

var logHandler LogKitHandler

func init() {
	logJobCh = make(chan *LogInfo)
	go handleLogkitJob(logJobCh)
}

func CloseLogKit() {
	close(logJobCh)
}

func RegisterHandler(h LogKitHandler) {
	logHandler = h
}

func EmitLog(level logrus.Level, time time.Time, title string, nodeId string) error {
	var levelStr string
	switch level {
	case logrus.DebugLevel:
		levelStr = "DEBUG"
	case logrus.InfoLevel:
		levelStr = "INFO"
	case logrus.WarnLevel:
		levelStr = "WARN"
	case logrus.ErrorLevel:
		levelStr = "ERROR"
	default:
		err := fmt.Errorf("level:%s not support", level)
		return err
	}

	logJobCh <- &LogInfo{Title: title,
		Level: levelStr,
		Time:  util.ISOString(time),
		Data:  logData{Node: nodeId},
	}
	return nil
}

func handleLogkitJob(logCh chan *LogInfo) {
	for l := range logCh {
		if logHandler != nil {
			err := logHandler(l)
			if err != nil {
				fmt.Println(err)
			}
		} else {
			fmt.Println("no logkit handler")
		}
	}
}

func GetLogkitUrl(masterUrl string) string {
	if masterUrl != "" {
		return masterUrl + "/internal/logkit/append"
	} else {
		return ""
	}
}

func LogKitHttpPostHandler(info *LogInfo) error {
	var logs [1]LogInfo = [1]LogInfo{*info}
	//logs = append(logs, *info)
	jsonRaw, err := json.Marshal(logs)
	if err != nil {
		return err
	}

	url := GetLogkitUrl(common.GetServiceMasterUrl())
	return PostLogkitDataByHttpMaster(url, common.GetAppId(), jsonRaw)
}

func PostLogkitDataByHttpMaster(url string, appid string, data []byte) error {
	jsonStr, err := json.Marshal(&logKitPostMasterData{
		Appid: appid,
		Logs:  data,
	})
	if err != nil {
		return err
	}

	if url == "" {
		return errors.New("cannot post log kit data, uri build failed")
	}

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
	req.Header.Set("Content-Type", "application/json")
	if err != nil {
		return err
	}

	resp, err := common.GetHttpClient().Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		err = fmt.Errorf("http post failed, remote response not success,status code%s", resp.Status)
		return err
	}

	return nil
}

func LogkitFireFunc(entry *logrus.Entry, hook *suanpan_log.SuanpanLogHook) error {
	msg := entry.Message
	if entry.Data != nil && len(entry.Data) != 0 {
		fieldData, _ := json.Marshal(&entry.Data)
		msg = entry.Message + string(fieldData)
	}
	err := EmitLog(entry.Level, entry.Time, msg, common.GetNodeId())
	if err != nil {
		return err
	}
	return nil
}
